#include "BankSystem.hh"
#include <iostream>
#include <iomanip>
#include <limits>
#include <string>
#include <ctime>
#include <sstream>
#include <regex>
#ifdef _WIN32
#include <cstdlib>
#define CLEAR_SCREEN "cls"
#else
#define CLEAR_SCREEN "clear"
#endif
#include "tool.hh"


int main() {
    BankSystem bank;
    while (true) {
        clearScreen();
        std::cout << "\n===== Banking System =====\n";
        std::cout << "1. Register new customer\n";
        std::cout << "2. Access customer accounts\n";
        std::cout << "3. Display all bank accounts\n";
        std::cout << "4. Transaction reports\n";
        std::cout << "5. Exit\n";
        std::cout << "Please choose: ";

        int choice = getValidChoice(5);
        if (choice == 5) break;

        clearScreen();
        switch (choice) {
            case 1: {
                std::cout << "\n===== Register New Customer =====\n";
                std::cout << "Enter customer name: ";
                std::string name = getValidName();
                bank.registerCustomer(name);
                std::cout << "Press Enter to continue...";
                std::cin.get();
                break;
            }
            case 2: {
                std::cout << "\n===== Access Customer Accounts =====\n";
                std::cout << "Enter customer name: ";
                std::string name = getValidName();
                Customer* customer = bank.findCustomer(name);
                if (!customer) {
                    std::cout << "Error: Customer not found.\n";
                    std::cout << "Press Enter to continue...";
                    std::cin.get();
                    break;
                }

                while (true) {
                    clearScreen();
                    std::cout << "\n===== Customer: " << name << " =====\n";
                    std::cout << "This customer has the following accounts:\n\n";
                    std::cout << "1. Savings Account: " << customer->getSavingsAccount()->getAccountId() << "\n";
                    std::cout << "   Balance: " << std::fixed << std::setprecision(2)
                              << customer->getSavingsAccount()->getBalance() << "\n\n";
                    std::cout << "2. Checking Account: " << customer->getCheckingAccount()->getAccountId() << "\n";
                    std::cout << "   Balance: " << std::fixed << std::setprecision(2)
                              << customer->getCheckingAccount()->getBalance() << "\n\n";
                    std::cout << "Options:\n";
                    std::cout << "1. Access Savings Account\n";
                    std::cout << "2. Access Checking Account\n";
                    std::cout << "3. View all transactions for this customer\n";
                    std::cout << "4. Generate customer report\n";
                    std::cout << "5. Return to main menu\n";
                    std::cout << "Please choose: ";

                    int subChoice = getValidChoice(5);
                    if (subChoice == 5) break;

                    clearScreen();
                    BankAccount* account = nullptr;
                    if (subChoice == 1) account = customer->getSavingsAccount();
                    else if (subChoice == 2) account = customer->getCheckingAccount();
                    else if (subChoice == 3) {
                        std::cout << "\nCustomer Transactions:\n";
                        std::cout << "Savings Account:\n";
                        std::cout << std::left << std::setw(10) << "ID"
                                  << std::setw(20) << "Date"
                                  << std::setw(15) << "Type"
                                  << std::setw(10) << "Amount"
                                  << "Note\n";
                        std::cout << std::string(65, '-') << "\n";

                        for (const auto& t : customer->getSavingsAccount()->getTransactions()) {
                            std::cout << std::left << std::setw(10) << t.getTransactionId()
                                      << std::setw(20) << t.getDate()
                                      << std::setw(15) << t.getType()
                                      << std::fixed << std::setprecision(2) << std::setw(9) << t.getAmount()
                                      << t.getNote() << "\n";
                        }

                        std::cout << "\nChecking Account:\n";
                        std::cout << std::left << std::setw(10) << "ID"
                                  << std::setw(20) << "Date"
                                  << std::setw(15) << "Type"
                                  << std::setw(10) << "Amount"
                                  << "Note\n";
                        std::cout << std::string(65, '-') << "\n";

                        for (const auto& t : customer->getCheckingAccount()->getTransactions()) {
                            std::cout << std::left << std::setw(10) << t.getTransactionId()
                                      << std::setw(20) << t.getDate()
                                      << std::setw(15) << t.getType()
                                      << std::fixed << std::setprecision(2) << std::setw(9) << t.getAmount()
                                      << t.getNote() << "\n";
                        }
                        std::cout << "Press Enter to continue...";
                        std::cin.get();
                        continue;
                    }
                    else if (subChoice == 4) {
                        std::time_t now = std::time(nullptr);
                        std::stringstream ss;
                        ss << "transactions_" << name << "_" << std::put_time(std::localtime(&now), "%Y-%m-%d") << ".txt";
                        customer->generateReport(ss.str());
                        std::cout << "Press Enter to continue...";
                        std::cin.get();
                        continue;
                    }

                    while (true) {
                        clearScreen();
                        std::cout << "\n===== Bank Account: " << account->getAccountId() << " (" << account->getAccountType() << ") =====\n";
                        std::cout << "Account holder: " << account->getOwnerName() << "\n";
                        std::cout << "Balance: " << std::fixed << std::setprecision(2) << account->getBalance() << "\n\n";
                        std::cout << "1. Deposit\n";
                        std::cout << "2. Withdraw\n";
                        std::cout << "3. Transfer\n";
                        std::cout << "4. View transaction history\n";
                        std::cout << "5. Generate bank account report\n";
                        std::cout << "6. Return to customer page\n";
                        std::cout << "Please choose: ";

                        int accountChoice = getValidChoice(6);
                        if (accountChoice == 6) break;

                        clearScreen();
                        switch (accountChoice) {
                            case 1: {
                                std::cout << "\n===== Deposit to Account: " << account->getAccountId() << " =====\n";
                                std::cout << "Current Balance: " << std::fixed << std::setprecision(2) << account->getBalance() << "\n";
                                std::cout << "Enter amount to deposit: ";
                                double amount = getValidAmount();
                                std::cout << "Add note (optional): ";
                                std::string note;
                                std::getline(std::cin, note);
                                account->deposit(amount, note);
                                std::cout << "Press Enter to continue...";
                                std::cin.get();
                                break;
                            }
                            case 2: {
                                std::cout << "\n===== Withdraw from Account: " << account->getAccountId() << " =====\n";
                                std::cout << "Current Balance: " << std::fixed << std::setprecision(2) << account->getBalance() << "\n";
                                std::cout << "Enter amount to withdraw: ";
                                double amount = getValidAmount();
                                std::cout << "Add note (optional): ";
                                std::string note;
                                std::getline(std::cin, note);
                                account->withdraw(amount, note);
                                std::cout << "Press Enter to continue...";
                                std::cin.get();
                                break;
                            }
                            case 3: {
                                std::cout << "\n===== Transfer from Account: " << account->getAccountId() << " =====\n";
                                std::cout << "Current Balance: " << std::fixed << std::setprecision(2) << account->getBalance() << "\n";
                                std::cout << "Enter destination account ID: ";
                                std::string destId;
                                std::getline(std::cin, destId);
                                std::regex pattern("^62(21|22)-[0-9]{4}-[0-9]{4}-[0-9]{4}$");
                                if (!std::regex_match(destId, pattern)) {
                                    std::cout << "Error: Invalid account ID format (e.g., 6221-XXXX-XXXX-XXXX).\n";
                                    std::cout << "Press Enter to continue...";
                                    std::cin.get();
                                    break;
                                }
                                BankAccount* destAccount = bank.findAccount(destId);
                                if (!destAccount) {
                                    std::cout << "Error: Destination account not found.\n";
                                    std::cout << "Press Enter to continue...";
                                    std::cin.get();
                                    break;
                                }
                                std::cout << "Enter amount to transfer: ";
                                double amount = getValidAmount();
                                std::cout << "Add note (optional): ";
                                std::string note;
                                std::getline(std::cin, note);
                                account->transferTo(destAccount, amount, note);
                                std::cout << "Press Enter to continue...";
                                std::cin.get();
                                break;
                            }
                            case 4: {
                                std::cout << "\nTransaction History:\n";
                                std::cout << std::left << std::setw(10) << "ID"
                                          << std::setw(20) << "Date"
                                          << std::setw(15) << "Type"
                                          << std::setw(10) << "Amount"
                                          << "Note\n";
                                std::cout << std::string(65, '-') << "\n";

                                for (const auto& t : account->getTransactions()) {
                                    std::cout << std::left << std::setw(10) << t.getTransactionId()
                                              << std::setw(20) << t.getDate()
                                              << std::setw(15) << t.getType()
                                              << std::fixed << std::setprecision(2) << std::setw(9) << t.getAmount()
                                              << t.getNote() << "\n";
                                }
                                std::cout << "Press Enter to continue...";
                                std::cin.get();
                                break;
                            }
                            case 5: {
                                std::time_t now = std::time(nullptr);
                                std::stringstream ss;
                                ss << "transactions_" << account->getAccountId() << "_" << std::put_time(std::localtime(&now), "%Y-%m-%d") << ".txt";
                                account->generateReport(ss.str());
                                std::cout << "Press Enter to continue...";
                                std::cin.get();
                                break;
                            }
                        }
                    }
                }
                break;
            }
            case 3:
                bank.displayAllAccounts();
                std::cout << "Press Enter to return to main menu...";
                std::cin.get();
                break;
            case 4:
                bank.generateGlobalReport();
                std::cout << "Press Enter to return to main menu...";
                std::cin.get();
                break;
        }
    }
    return 0;
}